package com.ruoyi.app.config.interceptor;

import cn.hutool.core.util.StrUtil;
import com.ruoyi.app.config.annotation.ReSubmitFilter;
import com.ruoyi.app.config.util.UserUtil;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.CommonUtils;
import com.ruoyi.common.redis.service.RedisService;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

/**
 * <p>
 * 作用：重复提交处理器
 * </p>
 *
 * @author zhanglianbao
 * @since 2025-02-06 21:23
 */
@Slf4j
@Component
public class ReSubmitInterceptor implements HandlerInterceptor {

  final ThreadLocal<String> lockKeyLocal = new ThreadLocal<>();
  @Value("${spring.application.name}")
  private String appName;
  @Resource
  private RedisService redisService;

  @Override
  public boolean preHandle(@Nonnull HttpServletRequest request,
      @Nonnull HttpServletResponse response, @Nonnull Object handler) throws Exception {
    // 检查handler是否是HandlerMethod的实例
    if (!(handler instanceof HandlerMethod)) {
      // 如果不是HandlerMethod的实例，则直接返回true，允许请求继续
      return true;
    }

    final HandlerMethod handlerMethod = (HandlerMethod) handler;
    final ReSubmitFilter reSubmitFilter = handlerMethod.getMethodAnnotation(ReSubmitFilter.class);
    if (reSubmitFilter != null) {
      // 创建锁
      final String key = reSubmitFilter.key();
      final Long userId = UserUtil.getUserId();
      //获得项目名称+接口+key+用户
      final String lockKey = StrUtil.format("LockKey:{}:{}:{}:{}", appName,
          request.getRequestURI(), key, userId);
      if (!redisService.setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS)) {
        throw new ServiceException("请求已收到，请耐心等待");
      }
      log.debug("=== 获得锁 ===[{}]", lockKey);
      lockKeyLocal.set(lockKey);
    }
    return true;
  }

  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
      Object handler, Exception ex) throws Exception {
    if (CommonUtils.hasText(lockKeyLocal.get())) {
      // 删除锁
      log.debug("=== 释放锁 ===[{}]", lockKeyLocal.get());
      redisService.deleteObject(lockKeyLocal.get());
      lockKeyLocal.remove();
    }
  }

}
